package IC;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;


//import java_cup.parser;

import IC.AST.ICClass;
import IC.AST.PrettyPrinter;
import IC.AST.Program;
import IC.LIR.SimpleTranslationVisitor;
import IC.LIR.TranslationVisitor;
import IC.Parser.LibraryParser;
import IC.Parser.Lexer;
import IC.Parser.parser;
import IC.Parser.Token;
import IC.Parser.sym;
import IC.Semantics.SemanticChecker;
import IC.Semantics.symbols.GlobalSymbolTable;
import IC.Semantics.types.TypeTable;

public class Compiler {
    
	private static Boolean p_ast= false;    				// for "-print-ast" flag
	private static Boolean flibic= false;    				// for "-L" (libic library) flag
	private static String libic_path =
			(new File("libic.sig").getAbsolutePath());	    // save libic.sig file path
	private static Boolean fdump_symtab = false;
	private static Boolean p_lir_code = false;

	public static void main(String[] args) 
	{
		if (args.length == 0) {
            System.out.println("Error: Bad arguments. missing input file argument.");
            System.exit(1);
		}
    
		// Check input command parameters
		for (int i = 1; i < args.length; i++){
            String s = args[i];
            if (s.equals("-print-ast")) { 					// "-print-ast" flag is given
            	if (p_ast) {                      
            		System.out.println("Error: Bad arguments. -print-ast flag is set more than once");
                    System.exit(1);
                } 
                else p_ast = true;
            }
            else if (s.startsWith("-L")) {           		// library class path is given
            	if (flibic) { 
            		System.out.println("Error: Bad arguments. -L flag is given more than once");
                    System.exit(1);
                } 
                else {
                	flibic = true;
                    libic_path = s.substring(2);
                }
            } 
            else if (s.startsWith("-dump-symtab")) {           		// library class path is given
            	if (fdump_symtab) { 
            		System.out.println("Error: Bad arguments. -dump-symtab flag is given more than once");
                    System.exit(1);
                } 
                else fdump_symtab = true;   
            } 
            else if (s.equals("-print-lir")) {                     //flag to print lir code on screen
            	if (p_lir_code) {
            		System.out.println("Error: Bad arguments. -print-lir flag is given more than once");
            		System.exit(1);
            	}
            	else p_lir_code = true;
            }
            else {
            	System.out.println("Error: Bad arguments.");
                System.exit(1);
            }
		}
    
		
		File lib_file =  new File(libic_path);
		if (lib_file.exists()) {
		    //Parse libic.sig library
			java_cup.runtime.Symbol libicParseTree = new java_cup.runtime.Symbol(0);
			try {  					// Can throw LexicalError or SyntaxError or I/O exeption
				FileReader libicFile = new FileReader(libic_path); 
				Lexer libicLexer = new Lexer(libicFile);
				LibraryParser libicParser = new LibraryParser(libicLexer);
				libicParseTree = libicParser.parse(); 
				System.out.println("Parsed " + libic_path + " successfully!");
			} 
			catch (Exception e) {
				System.err.print(e.getMessage());
				System.exit(1);
			}
		
		
			// Parse the given input file
			java_cup.runtime.Symbol ICParseTree = new java_cup.runtime.Symbol(1);
			try {			// Can throw LexicalError or SyntaxError or I/O exeption
    			FileReader icFile = new FileReader(args[0]); 
    			Lexer iclexer = new Lexer(icFile);
    			parser icParser = new parser(iclexer);
    			ICParseTree = icParser.parse(); 
    			System.out.println("Parsed " + args[0] + " successfully!");
			} 
    		catch (Exception e){
    			System.err.println(e.getMessage());
    			System.exit(1);
    		}
    
    		ICClass libicRoot = (ICClass) libicParseTree.value;
    		Program icRoot = (Program) ICParseTree.value;
    		
    		icRoot.addClassLibrary(libicRoot);
    	
    		// Check if needed to print the AST-Tree to System.out
    		if (p_ast){
    			PrettyPrinter printer = new PrettyPrinter(args[0]);
    			System.out.println(icRoot.accept(printer));
    		}
    		
    		
    		//build symbol & type table
    		SemanticChecker sc = new SemanticChecker(args[0]);
    		GlobalSymbolTable gst= (GlobalSymbolTable) icRoot.accept(sc);
    		if (gst==null)
    			System.exit(1);
    		 
    		if (fdump_symtab){
                 System.out.print("\n"+gst.dump());
                 System.out.print(TypeTable.dump(args[0]));
         	}
    		
    		//Translate to LIR code
    		if (p_lir_code) {
    			//Build the translation visitor
    			TranslationVisitor translationVisitor = new SimpleTranslationVisitor(gst);
    			
    			//Get the LIR code from the translator
    			String LirCodeTranslation = icRoot.accept(translationVisitor, 0).getCode();
    			
    			//Print the LIR code to an output file
    			String LirCodeOutputFile = args[0].substring(0,args[0].length()-2) + "lir";
    			try {
    				BufferedWriter writer = new BufferedWriter(new FileWriter(LirCodeOutputFile));
    				writer.write(LirCodeTranslation);
    				writer.flush();
    				writer.close();
    			} catch (IOException e) {
    				System.err.println("Failed to write LIR code to output file");
    				e.printStackTrace();
    			}
    			System.out.println("LIR code:");
    			System.out.println(LirCodeTranslation);
    		}
    		
		}
		else System.out.println("Error: no 'libic.sig' file existed.");
			
	}
	
	
	
}
